package com.yugao.fintech.draper.message.queue.support.broadcast;

import cn.hutool.core.util.TypeUtil;
import com.yugao.fintech.draper.message.queue.client.RedisMQTemplate;
import com.yugao.fintech.draper.message.queue.interceptor.RedisMessageInterceptor;
import com.yugao.fintech.draper.message.queue.message.AbstractMessage;
import com.yugao.fintech.draper.core.util.JacksonUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;

import java.lang.reflect.Type;
import java.util.List;

@Setter
@Getter
@Slf4j
public abstract class AbstractRedisBroadcastMessageListener<T extends RedisBroadcastMessage> implements MessageListener {
    /**
     * 消息类型
     */
    private final Class<T> messageType;

    /**
     * 主题topic
     */
    private final String topic;

    /**
     * RedisMQTemplate
     */
    private RedisMQTemplate redisMQTemplate;

    @SneakyThrows
    protected AbstractRedisBroadcastMessageListener() {
        this.messageType = getMessageClass();
        this.topic = messageType.newInstance().getTopic();
    }

    @Override
    public final void onMessage(Message message, byte[] bytes) {
        T messageObj = JacksonUtil.parseObject(message.getBody(), messageType);
        try {
            consumeMessageBefore(messageObj);
            // 消费消息
            this.onMessage(messageObj);
        } finally {
            consumeMessageAfter(messageObj);
        }
    }

    /**
     * 处理消息
     */
    public abstract void onMessage(T message);

    private Class<T> getMessageClass() {
        Type type = TypeUtil.getTypeArgument(getClass(), 0);
        if (type == null) {
            throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
        }
        return (Class<T>) type;
    }

    public void consumeMessageBefore(AbstractMessage message) {
        List<RedisMessageInterceptor> interceptors = redisMQTemplate.getInterceptors();
        interceptors.forEach(interceptor -> interceptor.consumeMessageBefore(message));
    }

    public void consumeMessageAfter(AbstractMessage message) {
        List<RedisMessageInterceptor> interceptors = redisMQTemplate.getInterceptors();
        for (int i = interceptors.size() - 1; i >= 0; i--) {
            interceptors.get(i).consumeMessageAfter(message);
        }
    }
}
